home *** CD-ROM | disk | FTP | other *** search
- #ifndef __serverTransPool_C__
- #define __serverTransPool_C__
- /*
- * $RCSfile: serverTransPool.C,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:30 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
-
- #include "Pool.h"
- #include "resources.h"
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "io.h"
- #include "page.h"
- #include "list.h"
- #include "object.h"
- #include "pool.h"
- #include "tid.h"
- #include "bf.h"
- #include "chunk.h"
- #include "bf_macro.h"
- #include "lock.h"
- #include "scan.h"
- #include "load.h"
- #include "msgdefs.h"
- #include "trans.h"
- #include "clog.h"
- #include "distr.h"
- #include "sm_state.h"
- #include "serverinfo.h"
- #include "trans_funcs.h"
- #include "msg_funcs.h"
- #include "clog_extfuncs.h"
- #include "trans_globals.h"
- #include "bf_intfuncs.h"
- #include "bf_extfuncs.h"
- #include "fi_extfuncs.h"
- #include "io_extfuncs.h"
- #include "scan.h"
- #include "sm_intfuncs.h"
- #include "sm_globals.h"
-
-
- void
- SERVERTRANSREC:: Init() {
- this->ReInit();
- initializeListElement( &(this->participants), this);
- initializeListElement( &(this->transList),this);
- };
- void
- SERVERTRANSREC:: ReInit() {
- this->tid = NULL_TID;
- this->serverTransState = T_INACTIVE;
- this->serverInfo = NULL;
- this->transRec = NULL;
- };
- LISTELEMENT *
- SERVERTRANSREC:: listlocation(int unique) {
- TRPRINT(TR_TRANS, TR_LEVEL_1, (" ", unique));
- SM_ASSERT(LEVEL_1, (unique == SERVERTRANS_POOL));
- return &(this->participants);
- }
-
- Pool<SERVERTRANSREC> *serverTransPool;
-
- void
- trans_Shutdown()
- {
- delete serverTransPool;
- serverTransPool = NULL;
- TransRec.clientTransState = T_INACTIVE;
- }
-
- int
- initTrans ()
- {
- TRACE(TR_TRANS, TR_LEVEL_1);
-
- TransRec.clientTid = NULL_TID;
- TransRec.clientTransState = T_INACTIVE;
- initializeList( &(TransRec.userDescList) );
- initializeList( &(TransRec.pageHashList) );
- initializeList( &(TransRec.bufGroupList) );
- initializeList( &(TransRec.lockHeaderList) );
- initializeList( &(TransRec.participants) );
- INIT_TRANSREC_MAGIC( &TransRec );
-
- serverTransPool = new Pool<SERVERTRANSREC> ( "serverTrans",
- SERVERTRANS_POOL, ServerTransPoolSize, POOL_NOMORE_GETMORE );
- if(serverTransPool == NULL) {
- SM_ERROR(TYPE_SYS, esmMALLOCFAILED);
- return esmFAILURE;
- }
-
- /*
- serverTransPool->Stats(stderr);
- */
-
- /* Record whether logging has been turned off for any file */
- fi_MarkLoggingOff();
-
- /* hints are not valid between transactions */
- fi_InvalidateHints();
-
- return esmNOERROR;
- }
-
- static BOOL
- ClearLogTailPage( SERVERTRANSREC *stl )
- {
- LOGINFO *logInfo = &(stl->serverInfo->logInfo);
-
- #ifdef DEBUG
- if (logInfo->tailBuffer != NULL) {
- SM_ASSERT(LEVEL_1,
- (logInfo->tailBuffer->hashList.hashPid.volid == logInfo->volid));
-
- SM_ASSERT(LEVEL_1, PAGE_IS_CLEAN(logInfo->tailBuffer));
- }
- TRPRINT(TR_LOG, TR_LEVEL_1, ("LOG %d not dirty", logInfo->volid));
-
- #endif DEBUG
- logInfo->tailBuffer = NULL;
-
- return FALSE;
- }
-
-
-
- SERVERTRANSREC *
- addTransServerInfo(
- TRANSREC *transRec,
- SERVERINFO *serverInfo
- )
- {
- SERVERTRANSREC *stl;
-
- TRPRINT(TR_TRANS, TR_LEVEL_1,
- ("Adding server %s to trans", serverInfo->hostName));
-
- stl = serverTransPool->Get();
- stl->serverInfo = serverInfo;
- stl->transRec = transRec;
- transRec->numParticipants ++;
- listEnq(&(transRec->participants), &(stl->participants));
- listEnq(&(serverInfo->transList), &(stl->transList));
-
- return stl;
- }
- void
- removeServerTransInfo(TRANSREC *transRec, void *msg)
- {
- MESSAGE *message = (MESSAGE *)msg;
- SERVERTRANSREC *stl;
-
- TRPRINT(TR_TRANS, TR_LEVEL_1, ("clearing servers from trans"));
-
- while((stl = (SERVERTRANSREC *)listDeq(&(transRec->participants)))!=NULL) {
- transRec->numParticipants --;
-
- if((message != NULL) && (stl->serverTransState == T_ACTIVE)) {
- TRPRINT(TR_TRANS, TR_LEVEL_1,
- ("sending message type %d to server %s",
- message->header.type, stl->serverInfo->hostName));
- message->header.params.in.tid = stl->tid;
-
- if (callServer(stl->serverInfo, message, NULL, 0 ) != esmNOERROR){
- /*
- * The only way callServer could fail is if the server
- * died, or if the transaction is already aborted. In
- * either case, the transaction will be aborted, so do
- * nothing special on error
- */
- }
- }
- /* remove this from the list of transactions considered
- * active on this server
- */
- listRemove(&(stl->transList));
- serverTransPool->Put( stl );
-
- }
- transRec->clientTransState = T_INACTIVE;
- }
-
- void
- endTransForAllServers(
- TRANSREC *transRec,
- int messageType
- )
- {
- MESSAGE message;
- message.header.type = messageType;
- message.header.replyRequested = TRUE;
- removeServerTransInfo(transRec, &message);
- }
-
- void
- ForEachServerInTrans(
- TRANSREC *transRec,
- int nargs,
- void *f,
- void *arg1,
- void *arg2,
- void *arg3,
- void *arg4,
- void *arg5,
- void *arg6
- )
- {
- FOREACHFUNC func = (FOREACHFUNC)f;
- SERVERTRANSREC *stl;
-
- TRPRINT(TR_TRANS, TR_LEVEL_1, ("sending to servers"));
- SM_ASSERT(LEVEL_1, (nargs <= 7));
- SM_ASSERT(LEVEL_1, (nargs >= 1));
-
- for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants));
- stl!=NULL;
- stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->participants)) ) {
-
- if ((*func)(stl, arg1, arg2, arg3, arg4, arg5, arg6))
- break; /* stop looking if found */
- }
- }
-
- void
- ForEachTrans(
- int nargs,
- void *func,
- void *arg1,
- void *arg2,
- void *arg3
- )
- {
- TRANSREC *transRec = findTransRec(getLocalTid());
-
- SM_ASSERT(LEVEL_1, (nargs <= 4));
- SM_ASSERT(LEVEL_1, (nargs >= 1));
-
- /* TODO: go through all trans recs, using the
- * generic ForEach function, which looks at nargs, but
- * passes only arg1, ... to the function.
- */
- (void) (*((FOREACHFUNC)func))(transRec, arg1, arg2, arg3);
- }
-
-
- int
- commandTrans (
- TRANSREC *transRec,
- COMMAND command
- )
- {
- MESSAGE message;
- int error;
- TRACE(TR_TRANS, TR_LEVEL_1);
-
- /*
- * We can proceed directly to make the call to the
- * coordinator as everything else should have been
- * done at prepare time
- */
- message.header.replyRequested = TRUE;
- message.header.type = CLIENT_COMMAND;
- message.header.params.in.tid = transRec->coordTid;
- message.body.command.command = command;
- /*
- * TODO - mention whether logging was turned on. ??
- */
- /* message.body.trans.loggingOn = LogInfo.loggingOn; */
-
- error = callServer(transRec->coordInfo, &message, NULL, 0 );
-
- /*
- The server's replies to a commandTrans are :
-
- esmTRANSDISABLED, (not done - i'm not done with recovery -
- try later)
- esmBADTRANSID, (i don't know about this trans so it must
- have been done already)
- esmNOTTRANSMASTER, (you can't tell me to do this so I won't -
- someone else must)
- esmBADCOMMAND (i didn't understand you so it's not been done
- internal error)
-
- esmTRANSNOTPREPARED so i ignored this commit request -
- fail but don't locally do anything
-
- esmTRANSABORTED transaction was aborted during commit.
-
- esmNOERROR (abort/commit done)
-
- If the server got disconnected, the client code can return
- esmSERVERDIED or esmNOTCONNECTED (doubtful):
- assume that it was not done and retry
- */
-
- if(error == esmNOERROR)
- return esmNOERROR;
-
- switch(sm_errno) {
-
- case esmSERVERDIED:
- case esmNOTCONNECTED:
- case esmTRANSDISABLED:
- /* might want to try again later */
- break; /* failed; leave tx active */
-
- case esmTRANSABORTED:
- case esmBADTRANSID:
- return esmNOERROR;
-
- case esmNOTTRANSMASTER:
- /* This might happen when a client crashes and a new client
- * comes up to tell the coordinator to finish the tx
- * TODO: We need to fix this on the server.
- */
- SM_ERROR(TYPE_CRASH, sm_errno);
-
- case esmTRANSNOTPREPARED:
- break; /* failed: leave tx active */
-
- case esmBADCOMMAND: /* internal (protocol) error */
- default: /* don't know what this situation is ! */
- SM_ERROR(TYPE_FATAL, sm_errno);
- }
- return esmFAILURE;
- }
-
- BEGIN_EXTERNC
- extern void sm_EndAllIndexLoads(TID);
- extern void sm_CloseAllLoadsAndScans();
- extern void sm_ReleaseAllUserDesc();
- END_EXTERNC
-
- static void
- endTrans(int how, TRANSREC *transRec)
- {
- sm_EndAllIndexLoads(transRec->clientTid);
- sm_CloseAllLoadsAndScans();
- sm_ReleaseAllUserDesc();
-
- closeBufferGroups();
- switch(how) {
- /* kludge - overload the transaction states to indicate which way we are ending the tx */
- case T_ABORT:
- bf_FlushAll( TRUE /*2nd arg doesn't matter */ ); /* discard */
- break;
- case T_COMMIT:
- case T_PREPARED:
- clog_ForceAllLogs(transRec);
- bf_FlushAll( FALSE, TRUE ); /* don't discard, skip temp vol pages */
- break;
- default:
- /* should not be possible */
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- ForEachServerInTrans( transRec, 1, ClearLogTailPage );
-
- #ifdef DEBUG
- if(how == T_ABORT)
- BF_AssertPageHashTableEmpty();
- #endif DEBUG
-
- /* Record whether logging has been turned off for any file */
- fi_MarkLoggingOff();
-
- /* hints are not valid between transactions */
- fi_InvalidateHints();
- }
-
-
-
- int
- commitTrans (
- TRANSREC *transRec
- )
- {
- MESSAGE message;
- SERVERINFO *serverInfo;
- int error;
- SERVERTRANSREC *stl;
-
- TRACE(TR_TRANS, TR_LEVEL_1);
-
- endTrans(T_COMMIT, transRec);
-
- /*
- * setup the commit transaction message.
- * mention whether logging was turned on.
- */
- message.header.type = COMMIT_TRANS;
- message.header.replyRequested = TRUE;
-
- if (transRec->numParticipants >= 1) {
- /*
- * there can only be a single server involved
- * else, either prepareTrans or commandTrans
- * would have benn called
- */
- SM_ASSERT(LEVEL_1, (transRec->numParticipants == 1));
-
- stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants));
-
- SM_ASSERT(LEVEL_1, (stl != NULL));
- message.header.params.in.tid = stl->tid;
- serverInfo = stl->serverInfo;
-
- /*
- * TODO - mention whether logging was turned on. ??
- */
- /* message.body.trans.loggingOn = LogInfo.loggingOn; */
-
- message.body.trans.syncTrans = FALSE;
-
- /* request server to commit the transaction */
- error = callServer(serverInfo, &message, NULL, 0 );
-
- /*
- The server's replies to a commit are :
-
- esmTRANSDISABLED, (not done - i'm not done with recovery
- - try later)
- esmBADTRANSID, (i don't know about this trans so it must
- have been done already)
-
- esmTRANSABORTED transaction was aborted during commit.
-
- esmNOTTRANSMASTER, (you can't tell me to do this so I
- won't - someone else must)
- esmBADCOMMAND (i didn't understand you so it's not been
- done internal error)
-
- esmTRANSNOTPREPARED so i ignored this commit request -
- fail but don't locally do anything
- esmNOERROR (abort/commit done)
-
- If the server got disconnected, the client code can return
- esmSERVERDIED or esmNOTCONNECTED (doubtful):
- assume that it was not done and retry
- */
- if (error != esmNOERROR) {
- switch(sm_errno) {
-
- case esmSERVERDIED:
- case esmNOTCONNECTED:
- /* might want to try again later */
- return esmFAILURE;
-
- case esmBADTRANSID:
- break; /* assume it worked; get rid of tx */
-
- case esmTRANSABORTED:
- break; /* it failed; keep the tx; user must abort it */
-
- case esmTRANSDISABLED:
- return esmFAILURE; /* failed; leave tx active */
-
- case esmNOTTRANSMASTER:
- case esmBADCOMMAND:
- case esmTRANSNOTPREPARED: /* should not happen: internal error */
- default: /* don't know what this situation is ! */
- SM_ERROR(TYPE_FATAL, sm_errno);
- }
- }
- }
- removeServerTransInfo(transRec, NULL);
-
- transRec->clientTransState = T_INACTIVE;
- transRec->clientTid = NULL_TID;
- transRec->coordTid = NULL_TID;
-
- return esmNOERROR;
- }
-
- int
- prepareTrans (
- TRANSREC *transRec,
- VOTE *vote,
- BOOL prepareAndCommit
- )
- {
- MESSAGE message;
- SERVERADDRTID serverAddrTid[MAXPARTICIPANTS];
- int numParticipants;
- SERVERTRANSREC *stl;
-
- TRACE(TR_TRANS, TR_LEVEL_1);
- TRPRINT(TR_SM|TR_TRANS|TR_DISTR, TR_LEVEL_1,
- ("prepareTrans: transRec->numParticipants:%d",
- transRec->numParticipants));
-
- endTrans(T_PREPARED, transRec);
-
- /*
- * take care of case where we haven't yet chosen a coord
- */
- if (transRec->coordTid == NULL_TID) {
- (void) pickCoord(transRec); /* can't return in error */
- }
-
- /*
- * Make sure that we're in sync with all the servers
- * (which is to say, they've got the last log pages and
- * the last data pages).
- * Do this before we tell the coord to do anything
- * but as late as possible so that while the pages are
- * being flushed to the server, we might get something
- * else done here.
- */
- io_SyncTrans(transRec, FALSE);
-
- /*
- * set up the prepare message for the coordinator
- */
- message.header.type = COORD_PREPARE_TRANS;
- message.header.replyRequested = TRUE;
- message.header.params.in.tid = transRec->coordTid;
-
- /*
- * set up the list of SERVERADDRTIDs to send with the
- * prepare message
- */
- for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants)),
- numParticipants = 0;
-
- stl != NULL;
- numParticipants++,
- stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->participants))
- ) {
-
- serverAddrTid[numParticipants].tid = stl->tid;
- serverAddrTid[numParticipants].connectAddr =
- stl->serverInfo->connectAddr;
- }
-
- SM_ASSERT(LEVEL_1, (transRec->numParticipants == numParticipants));
-
- message.body.prepare.numParticipants = numParticipants;
- message.body.prepare.prepareAndCommit = prepareAndCommit;
-
- /* request server to prepare the transaction */
- if (callServer(transRec->coordInfo, &message, (char *) serverAddrTid ,
- numParticipants * sizeof(SERVERADDRTID))
- != esmNOERROR) {
-
- /* esmTRANSDISABLED - could try again
- esmNOFREESERVERTIDINFO ditto
- esmLOGDISABLED no log; can't do it now - ditto
- esmBADTRANSID no dice: better abort
- esmNOTTRANSMASTER never : TODO FIX THIS ON SERVER
- esmTOOMANYSERVERS never: better abort
- esmTRANSCOMMITTED already committed
- esmTRANSABORTED already aborted
- myriad others no dice: better abort
- */
- switch(sm_errno) {
- case esmNOTCONNECTED:
- case esmSERVERDIED:
- case esmTRANSDISABLED:
- case esmNOFREESERVERTIDINFO:
- case esmLOGDISABLED:
- /* let user try again later */
- return esmFAILURE;
-
- case esmTRANSCOMMITTED:
- *vote = READVOTE;
- break;
- case esmTRANSABORTED:
- default:
- *vote = NOVOTE; /* kludge */
- break;
- }
- } else {
- *vote = message.body.vote.vote;
- }
-
- if(*vote == NOVOTE) {
- /* aborted : user must do an abort */
-
- transRec->clientTransState = T_ABORT;
- SM_TRANSABORTED(TYPE_USER, esmTRANSNOTPREPARED);
- return esmFAILURE;
-
- } else if(*vote == READVOTE) {
-
- /* committed */
- transRec->clientTransState = T_INACTIVE;
- transRec->clientTid = NULL_TID;
- transRec->coordTid = NULL_TID;
- }
- /* a prepared tx has no reason to hang onto any of its participants info*/
- removeServerTransInfo(transRec, NULL);
-
- return esmNOERROR;
- }
-
- int
- abortTrans (
- TRANSREC *transRec
- )
- /*
- * This routine will be called only in the case of a transaction
- * which is single server and has not been prepared.
- * In case there are multiple servers, each will be contacted
- * separately using endTransForAllServers() or through
- * the coordinator using commandTrans()
- */
- {
- TRACE(TR_TRANS, TR_LEVEL_1);
-
- endTrans(T_ABORT, transRec);
-
- endTransForAllServers(transRec, ABORT_TRANS);
- transRec->clientTid = NULL_TID;
- transRec->coordTid = NULL_TID;
-
- return esmNOERROR;
- }
-
- void
- ForEachTransOnServer(
- SERVERINFO *serverInfo,
- int nargs,
- void *f,
- void *arg1,
- void *arg2,
- void *arg3
- )
- {
- FOREACHFUNC func = (FOREACHFUNC)f;
- SERVERTRANSREC *stl;
-
- SM_ASSERT(LEVEL_1, (nargs <= 4));
- SM_ASSERT(LEVEL_1, (nargs >= 1));
-
- for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(serverInfo->transList));
- stl!=NULL;
- stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->transList)) ) {
-
- if ((*func)(stl, arg1, arg2, arg3))
- /* stop looking if found */
- break;
- }
- }
-
- static BOOL
- abortTransIfMatches(SERVERTRANSREC *stl, TID tid)
- {
- if((tid != NULL_TID) && (stl->tid != tid))
- return FALSE; /* keep looking */
-
- CLIENT_ABORT_TRANS(stl->transRec);
- return TRUE;
- }
-
- void
- serverAbortedTrans(SERVERINFO *serverInfo, TID tid)
- {
- ForEachTransOnServer(serverInfo, 2, abortTransIfMatches, (void *)tid, 0, 0);
- }
-
- #endif __serverTransPool_C__
-